#include "MHouse.h"


MHouse::MHouse(void)
{
	name = "House";
	points = new MVertex[9];
	normal = new MVertex[9];
	points[0] = MVertex(0,2,0);
	points[1] = MVertex(-1,1,1);
	points[2] = MVertex(1,1,1);
	points[3] = MVertex(1,1,-1);
	points[4] = MVertex(-1,1,-1);
	points[5] = MVertex(-1,-1,1);
	points[6] = MVertex(1,-1,1);
	points[7] = MVertex(1,-1,-1);
	points[8] = MVertex(-1,-1,-1);
	normal[0] = MVertex(0,1,0);
	calculateNormal(&normal[1],points[1],points[4],points[5],points[4],points[2]);
	calculateNormal(&normal[2],points[2],points[1],points[6],points[1],points[3]);
	calculateNormal(&normal[3],points[3],points[2],points[7],points[2],points[4]);
	calculateNormal(&normal[4],points[4],points[3],points[8],points[3],points[1]);
	calculateNormal(&normal[5],points[5],points[1],points[8],points[8],points[6]);
	calculateNormal(&normal[6],points[6],points[2],points[5],points[5],points[7]);
	calculateNormal(&normal[7],points[7],points[3],points[6],points[6],points[8]);
	calculateNormal(&normal[8],points[8],points[4],points[7],points[7],points[5]);
	//own axis
	v1 = MVertex(0,-1,0);
	v2 = MVertex(points[0]);
}


MHouse::~MHouse(void)
{
	delete []points;
	delete []normal;
}

void MHouse::drawShape(){

}


void MHouse::drawHouse(void(*func)(const MVertex &p1,  const MVertex &p2, const MVertex &p3, int ic),
								void(*drawline)(const MVertex &p1,  const MVertex &p2,int ic)) {
	if(!func || !points) {
		return;
	}
	func(points[0],points[1],points[2],1);
	func(points[0],points[2],points[3],4);
	func(points[0],points[3],points[4],8);
	func(points[0],points[4],points[1],7);

	func(points[2],points[6],points[3],5);
	func(points[3],points[6],points[7],5);
	func(points[3],points[7],points[8],2);
	func(points[8],points[3],points[4],2);
	func(points[4],points[8],points[1],3);
	func(points[1],points[8],points[5],3);
	func(points[2],points[1],points[5],1);
	func(points[2],points[5],points[6],1);	

	if(bNormal && drawline) {
		for(int i = 0; i < 9; i++)
			drawline(points[i],points[i]+normal[i]*NORMALEN,1);
	}
}

void MHouse::incrementSlice() {

}

void MHouse::decrementSlice() {

}

void MHouse::incrementStack() {

}

void MHouse::decrementStack() {

}

void MHouse::translate(float x, float y, float z) {
	if(points) {
		for(int i=0; i<9; i++) {
			points[i] = points[i].translate(x,y,z);
		}
		v1 = v1.translate(x,y,z);
		v2 = v2.translate(x,y,z);
	}
}

void MHouse::rotate(float deg, int x, int y, int z) {
	float theta = deg/180*PI;
	if(x==1) {
		for(int i=0; i<9; i++) {
				points[i] = points[i].rotateX(theta);
				normal[i] = normal[i].rotateX(theta);
		}
		v1 = v1.rotateX(theta);
		v2 = v2.rotateX(theta);
	}
	if(y==1) {
		for(int i=0; i<9; i++) {
			points[i] = points[i].rotateY(theta);
			normal[i] = normal[i].rotateY(theta);
		}
		v1 = v1.rotateY(theta);
		v2 = v2.rotateY(theta);
	}
	if(z==1) {
		for(int i=0; i<9; i++) {
			points[i] = points[i].rotateZ(theta);
			normal[i] = normal[i].rotateZ(theta);
		}
		v1 = v1.rotateZ(theta);
		v2 = v2.rotateZ(theta);
	}
}

void MHouse::scale(float x, float y, float z){
	if(points) {
		for(int i=0; i<9; i++) {
			points[i] = points[i].scaling(x,y,z);
		}
		v1 = v1.scaling(x,y,z);
		v2 = v2.scaling(x,y,z);
	}
}

void MHouse::rotateAroundOwnAxis(float theta) {
	MMatrix mT, mM, mR, mMb, mTb;
	//set translate matrix
	mT.setMatrix(1,0,0,-v1.point[0],0,1,0,-v1.point[1],0,0,1,-v1.point[2],0,0,0,1);
	//set translate back matrix
	mTb.setMatrix(1,0,0,v1.point[0],0,1,0,v1.point[1],0,0,1,v1.point[2],0,0,0,1);
	//get its own world axis
	MVertex u = getVertex(v1,v2).normailize(); //u match to +x
	MVertex n,v;
	if(isEqual(u.point[0],0) && isEqual(u.point[2],0)) {//if u is the same as up vector
		if(isEqual(u.point[1],1)) {
			n = MVertex(1,0,0);
			v = MVertex(0,0,1);
		}
		else if(isEqual(u.point[1],-1)) {
			n = MVertex(0,0,1);
			v = MVertex(1,0,0);
		}
		else {
			fprintf(stderr,"rotateAroundOwnAxis error\n");
		}
	}
	else {
		n = u.CrossProduct(MVertex(0,1,0)).normailize(); //n match to +z
		v = n.CrossProduct(u).normailize(); //v match to +y
	}
	//set rotation matrix turn vertex from own axis to world axis
	mM.setMatrix(u.point[0], u.point[1], u.point[2], 0,
		v.point[0], v.point[1], v.point[2], 0,
		n.point[0], n.point[1], n.point[2],0,
		0,0,0,1);
	//set rotation matrix turn vertex from world axis to its own world
	mMb.setMatrix(u.point[0], v.point[0], n.point[0], 0,
		u.point[1], v.point[1], n.point[1], 0,
		u.point[2], v.point[2], n.point[2], 0,
		0,0,0,1);
	//set rotation matrix rotate vertex around x axis which is the central axis
	mR.setMatrix(1,0,0,0,
		0,cos(theta),-sin(theta),0,
		0,sin(theta),cos(theta),0,
		0,0,0,1);

	//now, get the final magic matrix
	//matrix = mTb * mMb * mR * mM * mT
	MMatrix normalRotation = mMb.dotMatrix(mR).dotMatrix(mM);
	matrix = mTb.dotMatrix(normalRotation).dotMatrix(mT);
	if(points && normal) {
		for(int i=0; i<9; i++) {
				points[i] = matrix.dotVertex(points[i]);
				normal[i] = normalRotation.dotVertex(normal[i]);
		}
	}
}